Linked lists are widely used to link blocks of related data within computer memory and to identify blocks of memory that are available to store data. FIG. 1 depicts a series of available memory blocks 102 (also referred to as a “free” list) that are linked together by pointers 104 at the end of each block. The head of the free list is a free list pointer 106 that identifies the first free memory block and the end of the free list is identified by a “null” pointer. When memory blocks are needed to store data, the memory blocks are allocated in successive order from the free list by adjusting the free list pointer to exclude allocated memory blocks.
FIG. 2 depicts how the free list head pointer 206 is adjusted to exclude the first memory block 208 that has been allocated to store data. When a memory block is no longer needed to store data, the block can be added to the “head” or “front” of the free list by adjusting the free list head pointer to identify the newly freed memory block and by adjusting the pointer of the newly freed memory block to identify the next free memory block. Because newly freed memory blocks are added to the head of the list, the free integers are allocated on a last-in first-out (LIFO) basis. This technique for managing memory works well when the memory blocks are needed to store data, however it is not such an efficient technique for managing a list of integers that are available from an integer pool. Managing a list of integers instead of memory blocks is useful in several computing applications. For example, managing a list of integers is useful for allocating asynchronous transfer mode (ATM) virtual circuits (VCs) in an ATM network. Throughout the description, similar reference numbers may be used to identify similar elements.
U.S. Pat. No. 6,233,630 issued to Wilhelm discloses a technique for managing a list of free integers that is memory efficient. The technique involves defining an integer pool by pre-allocating a block of memory for every integer in the pool, with the memory block for every integer consisting entirely of a pointer that identifies the next integer in the linked list of free integers. That is, the integer pool consists entirely of links and therefore the amount of memory required to identify each integer is related to the size of the integer pool. For example 256 integers can be uniquely identified with eight bit pointers. FIG. 3 depicts a singly linked list of free integers where the integers consist entirely of pointers 304 that indicate the next integer in the list and where the first free integer in the list is indicated by a head element 306. The free integers are allocated in the order of the singly linked list. For example, when a free integer is needed, the next integer identified by the head element is allocated as indicated in FIG. 4. Allocating an integer (that is, removing the related element from the linked list) involves adjusting the pointer of the head element to identify the next element in the linked list as indicated in FIG. 5. When an allocated integer becomes freed and needs to be added back to the free list, the pointer of the head element is adjusted to identify the linked list element of the newly freed integer and the linked list element of the newly freed integer is adjusted to point to the integer that was previously identified by the head element.
While utilizing a singly linked list works well to identify a next free integer (i.e., where the next free integer can be any free integer from the integer pool), a singly linked list is not as efficient when a specific integer must be allocated from an integer pool, for example, when trying to reserve a specific ATM VC. A problem involved with allocating a specific integer using a singly linked list is that repairing the linked list of elements is an O(n) operation, where n is the number of integers in the integer pool. That is, allocating a specific integer (for example integer four) involves indexing into the array of linked list elements to the linked list element that represents integer four and then removing the linked list element from the linked list of elements. Removing a specific element from the linked list involves adjusting the pointer value of the element that is directly previous to the specific element to skip over the specific integer. For example, referring to FIG. 6, removing the element that relates to integer four involves adjusting the pointer value of the previous element (i.e., adjusting the pointer for integer three to identify integer five). The problem involved with adjusting the pointer value of the previous element is that the location of the previous element is not readily known. Locating the previous element in a singly linked list is an O(n) operation that involves sequentially searching through the array of elements until the previous element is found. In time critical applications, it is desirable to avoid O(n) operations.
Although the technique described by Wilhelm is memory efficient, the technique involves pre-allocating a block of memory for every integer in the desired integer pool regardless of how many unique integers are currently being utilized by the particular application. For example, if an integer pool consists of one hundred unique integers, then one hundred memory blocks are pre-allocated even if only five unique integers are being utilized. In applications that require a large integer pool but exhibit low integer utilization, the amount of memory dedicated to unutilized integers can be significant. For example, certain telecommunications applications require a large number of uniquely identifiable VCs to be available for worst case scenarios, while actual utilization of the unique integers is typically a small fraction of the required number. Reducing the memory requirements for managing an integer pool can free up memory for other uses and may reduce hardware costs.
Although the prior art discloses a memory efficient technique for allocating a unique integer from an integer pool, there is a need to be able to allocate specific integers as well as a next free integer in an efficient manner. In addition, there is a need to conserve the memory resources required to manage an integer pool, especially as the size of the integer pool increases. As a result, what is needed is an efficient way to allocate free integers from an integer pool that allows the selection of a specific free integer from an integer pool as well as the selection of any free integer from the integer pool and that conserves memory.